/********************************************************************************
 * @file    os_api.c
 * @author  jianqiang.xue
 * @version V1.1.0
 * @date    2023-03-01
 * @brief   NULL
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cmsis_compiler.h"
#include "cmsis_os.h"
#include "cmsis_os2.h"
#include "os_api.h"
#ifdef LISUN_SDK
#include "ls_syscfg.h"
#else
#define LS_MEMORY_SIZE   (512)
#endif

// Memory Heap Library functions
extern uint32_t osRtxMemoryInit (void *mem, uint32_t size);
extern void    *osRtxMemoryAlloc(void *mem, uint32_t size, uint32_t type);
extern uint32_t osRtxMemoryFree (void *mem, void *block);
#pragma pack(8)
static uint64_t g_heap_size[LS_MEMORY_SIZE/8];
#pragma pack()
uint8_t g_mem_init = false;

__asm(".global __use_no_heap_region\n\t"); //声明不使用C库的堆
void* malloc(size_t size) {
    return os_malloc(size);
}

void free(void* p) {
    os_free(p);
}
/* Public function prototypes -----------------------------------------------*/
/*********************************OS_KERNEL***********************************/
os_status os_kernel_initialize(void) {
    if (osRtxMemoryInit(g_heap_size, LS_MEMORY_SIZE))
        g_mem_init = true;
    return (os_status)osKernelInitialize();
}

os_status os_kernel_start(void) {
    return (os_status)osKernelStart();
}

os_status os_kernel_lock(void) {
    return (os_status)osKernelLock();
}

os_status os_kernel_unlock(void) {
    return (os_status)osKernelUnlock();
}

os_status os_delay(uint32_t ms) {
    return (os_status)osDelay(ms);
}

uint32_t os_get_tick(void) {
    return osKernelGetTickCount();
}
static bool mem_lock = false;
void* os_malloc(uint32_t size) {
    if (mem_lock || !g_mem_init) return NULL;
    //__asm volatile ("cpsid i" : : : "memory");
    mem_lock = true;
    char *p = osRtxMemoryAlloc(g_heap_size, size, 0);
    //__asm volatile ("cpsie i" : : : "memory");
    mem_lock = false;
    return p;
}

void* os_calloc(uint32_t size) {
    if (mem_lock || !g_mem_init) return NULL;
    mem_lock = true;
    //__asm volatile ("cpsid i" : : : "memory");
    char *p = osRtxMemoryAlloc(g_heap_size, size, 0);
    //__asm volatile ("cpsie i" : : : "memory");
    mem_lock = false;
    return p;
}

void os_free(void *p) {
    if (!g_mem_init) return;
    __asm volatile ("cpsid i" : : : "memory");
    osRtxMemoryFree(g_heap_size, p);
    __asm volatile ("cpsie i" : : : "memory");
}

mem_info_t* os_get_memory_info(void) {
    if (!g_mem_init) return NULL;
    return (mem_info_t*)g_heap_size;
}
/************************************OS_THREAD************************************/
os_thread_id os_thread_create(const os_thread_def_t* thread_def, void* arg) {
    if (thread_def == NULL)
        return NULL;

    osThreadAttr_t attr = {0};
    attr.name = arg;
    attr.priority = osPriorityLow;
    if (thread_def->tpriority == OS_PRIORITY_LOW)
        attr.priority = osPriorityLow;
    else if (thread_def->tpriority == OS_PRIORITY_NORMAL)
        attr.priority = osPriorityNormal;
    else if (thread_def->tpriority == OS_PRIORITY_ABOVENORMAL)
        attr.priority = osPriorityAboveNormal;
    else if (thread_def->tpriority == OS_PRIORITY_HIGH)
        attr.priority = osPriorityHigh;
    else if (thread_def->tpriority == OS_PRIORITY_REALTIME)
        attr.priority = osPriorityRealtime;
    else
        attr.priority = osPriorityLow;
    attr.stack_size = thread_def->stacksize;
    attr.attr_bits = osThreadDetached;
    return (os_thread_id)osThreadNew((osThreadFunc_t)thread_def->pthread, arg, &attr);
}

/************************************OS_TIMER************************************/
os_timer_id os_timer_create(const os_timer_def_t* timer_def, os_timer_t type, void* arg) {
    return osTimerNew((osTimerFunc_t)timer_def->ptimer, (os_timer_type)type, arg, NULL);
}

os_status os_timer_start(os_timer_id timer_id, uint32_t millisec) {
    return (os_status)osTimerStart(timer_id, millisec);
}

os_status os_timer_stop(os_timer_id timer_id) {
    if (osTimerIsRunning(timer_id))
        return (os_status)osTimerStop(timer_id);
    else
        return OS_OK;
}

bool os_timer_is_running(os_timer_id timer_id) {
    return osTimerIsRunning(timer_id);
}

os_status os_timer_restart(os_timer_id timer_id, uint32_t millisec) {
    if (osTimerIsRunning(timer_id)){
        osTimerStop(timer_id);
        return (os_status)osTimerStart(timer_id, millisec);
    } else {
        return (os_status)osTimerStart(timer_id, millisec);
    }
}

os_status os_timer_delete(os_timer_id timer_id) {
    return (os_status)osTimerDelete(timer_id);
}
/************************************OS_MAIL************************************/
os_mail_qid os_mail_create(const os_mailq_def_t* queue_def, os_thread_id thread_id) {
    return (os_mail_qid)osMessageQueueNew(queue_def->queue_sz, queue_def->item_sz, NULL);
}

void* os_mail_alloc(os_mail_qid queue_id, uint32_t millisec) {
    return NULL;
}

void* os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec) {
    return os_mail_alloc(queue_id, millisec);
}

os_status os_mail_put(os_mail_qid queue_id, void* mail) {
    return (os_status)osMessageQueuePut((osMessageQueueId_t)queue_id, mail, NULL, NULL);
}

os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void* arg) {
    osStatus_t status = osMessageQueueGet((osMessageQueueId_t)queue_id, arg, NULL, millisec);
    os_event event_t;
    event_t.status         = (os_status)status;
    event_t.def.message_id = (os_message_qid)queue_id;
    event_t.value.p        = arg;
    return event_t;
}

os_status os_mail_free(os_mail_qid queue_id, void* mail) {
    return (os_status)0;
}

/************************************OS_POOL************************************/
os_pool_id os_pool_create(const os_pool_def_t* pool_def) {
    return (os_pool_id)osPoolCreate((const osPoolDef_t*)pool_def);
}

void* os_pool_alloc(os_pool_id pool_id) {
    return osPoolAlloc((osPoolId)pool_id);
}

void* os_pool_calloc(os_pool_id pool_id) {
    return osPoolCAlloc((osPoolId)pool_id);
}

os_status os_pool_free(os_pool_id pool_id, void* block) {
    return (os_status)osPoolFree((osPoolId)pool_id, block);
}
/************************************OS_MSG_QUEUE************************************/
/**
 * @brief  [消息队列] 创建消息队列空间
 * @param  queue_def : 消息队列信息(大小)
 * @param  thread_id : 线程ID（可以无视不填）
 */
os_message_qid os_message_create(const os_messageq_def_t* queue_def, os_thread_id thread_id) {
    return (os_message_qid)osMessageCreate((const osMessageQDef_t*)queue_def, NULL);
}

/**
 * @brief  [消息队列] 发送一组消息队列数据
 * @param  queue_id: 消息队列ID
 * @param  info    : 消息指针
 * @param  millisec: 超时时间 0xFFFFFFFF 无限等待
 */
os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec) {
    return (os_status)osMessagePut((osMessageQId)queue_id, info, millisec);  // Send Message
}

/**
 * @brief  [消息队列] 得到一组消息队列数据
 * @param  queue_id: 消息队列ID
 * @param  millisec: 等待时间 0xFFFFFFFF 无限等待
 */
os_event os_message_get(os_message_qid queue_id, uint32_t millisec) {
    osEvent event;
    os_event event_t;
    event = osMessageGet((osMessageQId)queue_id, millisec);
    memcpy(&event_t, &event, sizeof(osEvent));
    return event_t;
}

/**
 * @brief  [消息队列] 得到当前剩余量
 * @param  queue_id: 消息队列ID
 * @retval 返回当前剩余量
 */
uint8_t os_message_get_space(os_message_qid queue_id) {
    return (uint8_t)osMessageQueueGetSpace(queue_id);
}

/**
 * @brief  [消息队列] 得到当前使用量
 * @param  queue_id: 消息队列ID
 * @retval 返回当前使用量
 */
uint8_t os_message_get_count(os_message_qid queue_id) {
    return (uint8_t)osMessageQueueGetCount(queue_id);
}
/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals) {
    return osSignalSet(thread_id, signals);
}

int32_t os_signal_set(os_thread_id thread_id, int32_t signals) {
    return osSignalSet(thread_id, signals);
}

int32_t os_signal_clear(os_thread_id thread_id, int32_t signals) {
    return osSignalClear(thread_id, signals);
}

// signals = 0,则等待任意信号.
os_event os_signal_wait(int32_t signals, uint32_t millisec) {
    osEvent event;
    os_event event_t;

    event = osSignalWait(signals, millisec);
    memcpy(&event_t, &event, sizeof(osEvent));
    return event_t;
}
